package service

import (
	"fmt"
	"go-admin/app/admin/service/dto"
	"go-admin/config"
	"os"
	"os/exec"
	"runtime"
	"strconv"
	"strings"

	"github.com/go-admin-team/go-admin-core/sdk/service"
	"gopkg.in/ini.v1"
	"gopkg.in/yaml.v3"
)

type SysBaseConfig struct {
	service.Service
}

type SipConfigData struct {
	Udp           string `yaml:"udp"`
	Wanudp        string `yaml:"wanudp"`
	Api           string `yaml:"api"`
	AudioPushPort int    `yaml:"audio_push_port"`
	Secret        string `yaml:"secret"`
	Media         struct {
		Restful string `yaml:"restful"`
		Http    string `yaml:"http"`
		Ws      string `yaml:"WS"`
		Rtmp    string `yaml:"rtmp"`
		Rtsp    string `yaml:"rtsp"`
		Rtp     string `yaml:"rtp"`
		Secret  string `yaml:"secret"`
	} `yaml:"media"`
	GB28181 struct {
		Lid    string `yaml:"lid"`
		Region string `yaml:"region"`
		Pwd    string `yaml:"pwd"`
	} `yaml:"gb28181"`
}

type ZlmApi struct {
	Secret string `ini:"secret"`
}

type ZlmGeneral struct {
	ServerId                string `ini:"mediaServerId"`
	StreamNoneReaderDelayMS int    `ini:"streamNoneReaderDelayMS"`
}

type ZlmHttp struct {
	Port int `ini:"port"`
}

type ZlmRtmp struct {
	Port int `ini:"port"`
}

type ZlmRtp struct {
	Port int `ini:"port"`
}

type ZlmRtsp struct {
	Port int `ini:"port"`
}

type ZlmWebhook struct {
	OnStreamChanged    string `ini:"on_stream_changed"`
	OnStreamNoneReader string `ini:"on_stream_none_reader"`
	OnStreamNotFound   string `ini:"on_stream_not_found"`
}

func (e *SysBaseConfig) GetConfig() (cfgData dto.SysBaseConfigData, err error) {
	cfgData = dto.SysBaseConfigData{
		ConfigType: "",
		Sip: dto.SipConfigData{
			ServerId:           "",
			DomainId:           "",
			Address:            "",
			Port:               0,
			Password:           "",
			WebApiPort:         0,
			WebApiSecret:       "",
			BroadcastStartPort: 0,
		},
		Media: dto.MediaConfigData{
			ServerId:              "",
			WebApiPort:            0,
			WebApiSecret:          "",
			UnwatchedCloseTimeout: 0,
			RtmpPort:              0,
			RtspPort:              0,
			RtpPort:               0,
		},
	}

	sipConfigFile, err := os.ReadFile(config.ExtConfig.GoSip.Configpath)
	if err != nil {
		return
	}
	var sipConfig SipConfigData
	err = yaml.Unmarshal(sipConfigFile, &sipConfig)
	if err != nil {
		return
	}

	serverId := sipConfig.GB28181.Lid
	region := sipConfig.GB28181.Region
	pwd := sipConfig.GB28181.Pwd
	sipApi := sipConfig.Api
	sipSecret := sipConfig.Secret
	sipWanUdp := sipConfig.Wanudp
	audio_push_port := sipConfig.AudioPushPort

	sipHost := strings.Split(sipWanUdp, ":")[0]
	sipPort, _ := strconv.Atoi(strings.Split(sipWanUdp, ":")[1])

	apiPort, _ := strconv.Atoi(strings.Split(sipApi, ":")[1])

	cfgData.Sip.ServerId = serverId
	cfgData.Sip.DomainId = region
	cfgData.Sip.Address = sipHost
	cfgData.Sip.Port = sipPort
	cfgData.Sip.Password = pwd
	cfgData.Sip.WebApiPort = apiPort
	cfgData.Sip.WebApiSecret = sipSecret
	cfgData.Sip.BroadcastStartPort = audio_push_port

	cfg, err := ini.Load(config.ExtConfig.ZLM.Configpath)
	if err != nil {
		fmt.Printf("Fail to read file: %v", err)
		return
	}
	zlmApi := ZlmApi{}
	err = cfg.Section("api").MapTo(&zlmApi)
	if err != nil {
		return
	}

	zlmGeneral := ZlmGeneral{}
	err = cfg.Section("general").MapTo(&zlmGeneral)
	if err != nil {
		return
	}

	zlmHttp := ZlmHttp{}
	err = cfg.Section("http").MapTo(&zlmHttp)
	if err != nil {
		return
	}

	zlmRtmp := ZlmRtmp{}
	cfg.Section("rtmp").MapTo(&zlmRtmp)

	zlmRtp := ZlmRtp{}
	cfg.Section("rtp_proxy").MapTo(&zlmRtp)

	zlmRtsp := ZlmRtsp{}
	cfg.Section("rtsp").MapTo(&zlmRtsp)

	cfgData.Media.ServerId = zlmGeneral.ServerId
	cfgData.Media.WebApiHost = sipHost
	cfgData.Media.WebApiPort = zlmHttp.Port
	cfgData.Media.WebApiSecret = zlmApi.Secret
	cfgData.Media.UnwatchedCloseTimeout = zlmGeneral.StreamNoneReaderDelayMS
	cfgData.Media.RtmpPort = zlmRtmp.Port
	cfgData.Media.RtspPort = zlmRtsp.Port
	cfgData.Media.RtpPort = zlmRtp.Port

	return cfgData, nil
}

func (e *SysBaseConfig) SetConfig(req dto.SysBaseConfigData) error {
	// 先读取配置文件
	sipConfigFile, err := os.ReadFile(config.ExtConfig.GoSip.Configpath)
	if err != nil {
		return err
	}
	var sipConfig map[string]any
	err = yaml.Unmarshal(sipConfigFile, &sipConfig)
	if err != nil {
		return err
	}
	cfg, err := ini.Load(config.ExtConfig.ZLM.Configpath)
	if err != nil {
		fmt.Printf("Fail to read file: %v", err)
		return err
	}
	switch req.ConfigType {
	case "sip":
		// 更新配置
		if sipConfig["gb28181"] == nil {
			sipConfig["gb28181"] = make(map[string]any)
		}
		sipConfig["gb28181"].(map[string]any)["lid"] = req.Sip.ServerId
		sipConfig["gb28181"].(map[string]any)["region"] = req.Sip.DomainId
		sipConfig["gb28181"].(map[string]any)["pwd"] = req.Sip.Password
		sipConfig["udp"] = fmt.Sprintf("%s:%d", "0.0.0.0", req.Sip.Port)
		sipConfig["wanudp"] = fmt.Sprintf("%s:%d", req.Sip.Address, req.Sip.Port)
		sipConfig["api"] = fmt.Sprintf("%s:%d", "0.0.0.0", req.Sip.WebApiPort)
		sipConfig["audio_push_port"] = req.Sip.BroadcastStartPort
		sipConfig["secret"] = req.Sip.WebApiSecret

		// 写入配置文件
		sipConfigFile, err = yaml.Marshal(&sipConfig)
		if err != nil {
			return err
		}
		// 写入文件
		err = os.WriteFile(config.ExtConfig.GoSip.Configpath, sipConfigFile, 0644)
		if err != nil {
			return err
		}
		// 更新流媒体配置文件的hook回调地址
		cfg.Section("hook").Key("on_stream_changed").SetValue(fmt.Sprintf("http://%s:%d/zlm/webhook/on_stream_changed", "localhost", req.Sip.WebApiPort))
		cfg.Section("hook").Key("on_stream_none_reader").SetValue(fmt.Sprintf("http://%s:%d/zlm/webhook/on_stream_none_reader", "localhost", req.Sip.WebApiPort))
		cfg.Section("hook").Key("on_stream_not_found").SetValue(fmt.Sprintf("http://%s:%d/zlm/webhook/on_stream_not_found", "localhost", req.Sip.WebApiPort))
		// 保存更改到文件
		err = cfg.SaveTo(config.ExtConfig.ZLM.Configpath)
		if err != nil {
			return err
		}
	case "media":
		// 更新SIP流媒体配置
		if sipConfig["media"] == nil {
			sipConfig["media"] = make(map[string]any)
		}
		sipConfig["media"].(map[string]any)["restful"] = fmt.Sprintf("http://%s:%d", req.Media.WebApiHost, req.Media.WebApiPort)
		sipConfig["media"].(map[string]any)["http"] = fmt.Sprintf("http://%s:%d", req.Media.WebApiHost, req.Media.WebApiPort)
		sipConfig["media"].(map[string]any)["WS"] = fmt.Sprintf("ws://%s:%d", req.Media.WebApiHost, req.Media.WebApiPort)
		sipConfig["media"].(map[string]any)["rtmp"] = fmt.Sprintf("rtmp://%s:%d", req.Media.WebApiHost, req.Media.RtmpPort)
		sipConfig["media"].(map[string]any)["rtsp"] = fmt.Sprintf("rtsp://%s:%d", req.Media.WebApiHost, req.Media.RtspPort)
		sipConfig["media"].(map[string]any)["rtp"] = fmt.Sprintf("rtp://%s:%d", req.Media.WebApiHost, req.Media.RtpPort)
		sipConfig["media"].(map[string]any)["secret"] = req.Media.WebApiSecret

		// 写入配置文件
		sipConfigFile, err = yaml.Marshal(&sipConfig)
		if err != nil {
			return err
		}
		// 写入文件
		err = os.WriteFile(config.ExtConfig.GoSip.Configpath, sipConfigFile, 0644)
		if err != nil {
			return err
		}
		// 更新流媒体配置文件
		cfg.Section("api").Key("secret").SetValue(req.Media.WebApiSecret)
		cfg.Section("general").Key("mediaServerId").SetValue(req.Media.ServerId)
		cfg.Section("general").Key("streamNoneReaderDelayMS").SetValue(strconv.Itoa(req.Media.UnwatchedCloseTimeout))
		cfg.Section("http").Key("port").SetValue(strconv.Itoa(req.Media.WebApiPort))
		cfg.Section("rtmp").Key("port").SetValue(strconv.Itoa(req.Media.RtmpPort))
		cfg.Section("rtsp").Key("port").SetValue(strconv.Itoa(req.Media.RtspPort))
		cfg.Section("rtp_proxy").Key("port").SetValue(strconv.Itoa(req.Media.RtpPort))

		// 保存更改到文件
		err = cfg.SaveTo(config.ExtConfig.ZLM.Configpath)
		if err != nil {
			return err
		}
	}
	// 重启服务
	if runtime.GOOS == "linux" {
		// 执行脚本，重启服务
		exec.Command("systemctl", "restart", config.ExtConfig.GoSip.Servername).Run()
		exec.Command("systemctl", "restart", config.ExtConfig.ZLM.Servername).Run()
	}
	return nil
}
